/**
 * 
 */
package com.mc.test;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.huaweicloud.sdk.core.auth.BasicCredentials;
import com.huaweicloud.sdk.core.auth.ICredential;
import com.huaweicloud.sdk.core.exception.ConnectionException;
import com.huaweicloud.sdk.core.exception.RequestTimeoutException;
import com.huaweicloud.sdk.core.exception.ServiceResponseException;
import com.huaweicloud.sdk.core.http.HttpConfig;
import com.huaweicloud.sdk.ocr.v1.OcrClient;
import com.huaweicloud.sdk.ocr.v1.model.GeneralTableRequestBody;
import com.huaweicloud.sdk.ocr.v1.model.RecognizeGeneralTableRequest;
import com.huaweicloud.sdk.ocr.v1.model.RecognizeGeneralTableResponse;
import com.huaweicloud.sdk.ocr.v1.region.OcrRegion;
import com.mc.file.Base64Util;
/**
 * @author w.weizhen
 *  
 *  表格图片通过huaweicloud识别生成表格文件
 *  表格文件通过EasyExcel解析生成json文件和sql文件
 *  
 */
public class ImgToExToJsonSql {
    private static final String path = "D:/文件/处理/";//工作路径
    private static final String img_path = "表格图片/";
    private static final String exc_path = "表格文件/";
    private static final String sql_path = "sql文件/";
    
    /**
     * @param args
     */
    public static void main(String[] args) {
        //表格图片识别生成表格文件
        //imgToEx();
        
        // 表格文件转为json和sql文件
        exToJsonSql();
        
    }
    
    //huaweicloud
    private static final String hwc_ak = "FNV2AAKWAJE7XJQCURKQ";
    private static final String hwc_sk = "8AD5Jz7jBZD0Uxbrq3wmEz7SK1E5aZJ6oa8f3R3O";
    //表格图片识别生成表格文件
    private static void imgToEx()
    {
        //图片路径，读取该路径下的图片文件和该路径下的文件夹下的图片文件。
        File imgPath = new File(path + img_path);
        //路径是否存在,并且是一个文件夹，然后得到文件和文件夹
        if (imgPath.exists()&&imgPath.isDirectory()) 
        {
            List<File> files = Arrays.asList(imgPath.listFiles());
            if(files==null||files.size()<1) {return;}
            //处理每一个目录
            for (int i = 0; i < files.size(); i++) 
            {
                File file = files.get(i);
                //是一个文件夹
                if(file.isDirectory())
                {
                    String name = file.getName();//文件夹名称
                    List<File> cfiles = Arrays.asList(file.listFiles());//文件夹下文件集合
                    if(cfiles==null||cfiles.size()<1) {continue;}
                    for (int j = 0; j < cfiles.size(); j++) 
                    {
                        File cfile = cfiles.get(j);
                        if(cfile.isFile())
                        {
                            //调用识别
                            recognizeGeneralTable(name, cfile);
                        }
                    }
                }
            }
        }
    }
    
    // 调用huaweicloud识别,得到json数据，然后调用方法生成表格文件
    // directory 如果是在次级目录中则传入次级目录名；file 表格图片。
    private static void recognizeGeneralTable(String directory, File file)
    {
        // 使用默认配置
        HttpConfig config = HttpConfig.getDefaultHttpConfig();
        // 初始化客户端认证信息，使用当前客户端初始化方式可不填 projectId/domainId
        ICredential auth = new BasicCredentials().withAk(hwc_ak).withSk(hwc_sk);
        // 初始化指定云服务的客户端 {Service}Client ，以初始化OCR服务的 OcrClient 为例
        OcrClient client = OcrClient.newBuilder().withHttpConfig(config).withCredential(auth).withRegion(OcrRegion.valueOf("cn-north-4")).build();
        
        // 以调用通用表格识别接口 RecognizeGeneralTable 为例
        RecognizeGeneralTableRequest request = new RecognizeGeneralTableRequest();
        GeneralTableRequestBody body = new GeneralTableRequestBody();
        //body.withUrl("图片的url");
        body.withImage(Base64Util.encryptToBase64(file.getPath()));
        request.withBody(body);
        try {
            RecognizeGeneralTableResponse response = client.recognizeGeneralTable(request);
            System.out.println(JSONObject.toJSONString(response));
            if (200 == response.getHttpStatusCode()) {
                //JSONObject data = JSONObject.parseObject(JSONObject.toJSONString(response));
                JSONArray datas = JSONArray.parseArray(JSONObject.toJSONString(response.getResult().getWordsRegionList()));
                //将解析内容生成表格文件
                writeExcel(directory, file.getName(), datas);
            }else {
                System.err.println(JSONObject.toJSONString(response));
            }
        } catch (ConnectionException e) {
            e.printStackTrace();
        } catch (RequestTimeoutException e) {
            e.printStackTrace();
        } catch (ServiceResponseException e) {
            e.printStackTrace();
            System.err.println(e.getHttpStatusCode());
            System.err.println(e.getErrorCode());
            System.err.println(e.getErrorMsg());
        }
    }
    
    // 将识别表格图片得到的json内容转换为表格文件
    // directory 如果是在次级目录中则传入次级目录名称，name 文件名， datas json数据。
    private static void writeExcel(String directory, String name, JSONArray datas)
    {
        name = name.substring(0, name.lastIndexOf("."));//去除名称的后缀
        //标题和内容
        List<List<String>> heads = new ArrayList<List<String>>();
        List<List<String>> words = new ArrayList<List<String>>();
        //生成一个空的表格
        int length = 20;
        for (int i = 0; i < length; i++) 
        {
            List<String> head = new ArrayList<String>();head.add("");
            List<String> word = new ArrayList<String>();
            for (int j = 0; j < length; j++) 
            {
                word.add("");
            }
            heads.add(head);
            words.add(word);
        }
        //填充内容
        for (int i = 0; i < datas.size(); i++) 
        {
            JSONObject data=datas.getJSONObject(i);
            //是不是空的内容
            if(data==null || data.getInteger("wordsBlockCount") < 2){continue;}
            
            JSONArray wordsBlocks = data.getJSONArray("wordsBlockList");
            for (int j = 0; j < wordsBlocks.size(); j++) 
            {
                JSONObject wordsBlock=wordsBlocks.getJSONObject(j);
                
                if ("table".equals(data.get("type"))) 
                {
                    List<Integer> columns = wordsBlock.getJSONArray("columns").toJavaList(Integer.class);
                    List<Integer> rows = wordsBlock.getJSONArray("rows").toJavaList(Integer.class);
                    String word = wordsBlock.getString("words");
                    word = word.replaceAll("\\r?\\n", "");//去除换行符
                    word = word.replaceAll("．", ".");//替换特殊符号
                    
                    for (int k = 0; k < columns.size(); k++) 
                    {
                        for (int k2 = 0; k2 < rows.size(); k2++) 
                        {
                            //words.get(rows.get(k2)).add(columns.get(k), word);
                            Integer row = rows.get(k2);
                            Integer column = columns.get(k);
                            
                            if (row < 1) {heads.get(column).set(row, word);}
                            if (row > 0) {words.get(row-1).set(column, word);}
                        }
                    }
                }
            }
        }
        
        //生成表格文件
        File file = new File(path + exc_path, directory);
        if(!file.exists()) {file.mkdir();}
        EasyExcel.write(file.getPath() + "/" + name + ".xlsx").head(heads).sheet("Sheet").doWrite(words);
    }
    
    // 表格文件转为json和sql文件
    private static void exToJsonSql()
    {
        //存在中类的部分
        List<Integer> middling = Arrays.asList(0,2,3,4,5,6,7,8);
        //存在检查小类的部分
        List<Integer> smell = Arrays.asList(4,5,6,7);
        //所有部分的次序名称
        JSONArray parts = new JSONArray();parts.add("第一部分");parts.add("第二部分");parts.add("第三部分");parts.add("第四部分");parts.add("第五部分");parts.add("第六部分");parts.add("第七部分");parts.add("第八部分");parts.add("第九部分");
        
        //指定路径，指定路径是否存在。
        File readPath = new File(path + exc_path);
        if (readPath.exists()) 
        {
            //指定路径下的目录集合，目录不为空
            List<File> directorys = Arrays.asList(readPath.listFiles());
            if(directorys==null||directorys.size()<1) {return;}
            //循环处理每一个目录
            for (int i = 0; i < directorys.size(); i++) 
            {
                File directory = directorys.get(i);
                //获取目录下的文件集合
                List<File> files = Arrays.asList(directory.listFiles());
                if(!directory.isDirectory()||files==null||files.size()<1) {continue;}//不是文件夹或者没有文件
                //排序,依照页码，排序文件，防止次序错误。
                Collections.sort(files, new Comparator<File>() {
                    @Override
                    public int compare(File o1, File o2) {
                        //String name1 = o1.getName().substring(0,o1.getName().lastIndexOf("."));
                        //String name2 = o2.getName().substring(0,o2.getName().lastIndexOf("."));
                        String name1 = o1.getName();
                        String name2 = o2.getName();
                        name1 = String.format("%10s", name1);
                        name2 = String.format("%10s", name2);
                        return name1.compareTo(name2);
                    }
                });
                for (int j = 0; j < files.size(); j++) {System.out.println(files.get(j).getName());}
                
                JSONArray catalogs = new JSONArray();//目录
                JSONArray items = new JSONArray();//检查项
                
                String directoryName = directory.getName();//目录名称是部分的名称[第一部分 XXXX、第二部分 XXXX 等]
                String[] splits = directoryName.split(" ");//分解
                int index = parts.indexOf(splits[0]);//计算“部分”的下标，用于判断是否有检查小类。
                //编码,1是固定开头，“部分”只有九个
                String no = "1"+(parts.indexOf(splits[0])+1);//计算“部分”的编号
                
                JSONObject catalog = new JSONObject();
                catalog.put("catalogNo", no);
                catalog.put("catalog", directoryName);
                catalog.put("display", 1);
                catalogs.add(catalog);
                
                //处理每一个文件
                for (int j = 0; j < files.size(); j++) 
                {
                    File file = files.get(j);
                    String name = file.getName();//目录名称是部分的名称[第一部分 XXXX、第二部分 XXXX 等]
                    if(!file.isFile()||name.indexOf("xls")<0) {continue;}//不是文件,或者不是表格文件
                    
                    // 这里 也可以不指定class，返回一个list，然后读取第一个sheet 同步读取会自动finish
                    List<Map<Integer, String>> listMap = EasyExcel.read(file.getPath()).sheet().doReadSync();
                    for (int v = 0; v < listMap.size(); v++) {
                        Map<Integer, String> data = listMap.get(v);
                        if(data==null||data.isEmpty()||StringUtils.isBlank(data.get(0))) {continue;}
                        // 返回每条数据的键值对 表示所在的列 和所在列的值
                        //System.out.println(name+": "+JSON.toJSONString(data));
                        //部分、大类、中类、小类是否存在，存在表示为目录、不存在添加
                        //大类
                        boolean isin = false;//是否已经存在
                        int num = 1;//计算已经有的数量，用于计算编码
                        String fatherNo = "";//上一级的编码
                        for (int k = 0; k < catalogs.size(); k++) 
                        {
                            if(data.get(0).equals(catalogs.getJSONObject(k).get("catalog"))) 
                            {
                                isin = true;
                                fatherNo = catalogs.getJSONObject(k).getString("catalogNo");
                                break;
                            }
                            String catalogNo = catalogs.getJSONObject(k).getString("catalogNo");
                            if(catalogNo.indexOf(no)==0&&!catalogNo.equals(no)&&catalogNo.length()==4)
                            {
                                num = num + 1;
                            }
                        }
                        if(!isin)
                        {
                            catalog = new JSONObject();
                            fatherNo = no+(num<10?"0"+num:num);
                            catalog.put("catalogNo", fatherNo);
                            catalog.put("catalog", data.get(0));
                            catalog.put("display", 1);
                            catalogs.add(catalog);
                        }
                        
                        //是否有中类
                        int isMiddling = middling.indexOf(index)>-1?1:0;//这里使用数字表示，数字在后面可用于数据获取。
                        if(isMiddling==1)
                        {
                            isin = false;//是否已经存在
                            num = 1;//计算已经有的数量，用于计算编码
                            for (int k = 0; k < catalogs.size(); k++) 
                            {
                                String catalogNo = catalogs.getJSONObject(k).getString("catalogNo");
                                if(data.get(1).equals(catalogs.getJSONObject(k).get("catalog"))&&catalogNo.equals(fatherNo+(num<10?"0"+num:num))) 
                                {
                                    isin = true;
                                    fatherNo = catalogs.getJSONObject(k).getString("catalogNo");
                                    break;
                                }
                                if(catalogNo.indexOf(fatherNo)==0&&!catalogNo.equals(fatherNo)&&catalogNo.length()==6)
                                {
                                    num = num + 1;
                                }
                            }
                            if(!isin)
                            {
                                catalog = new JSONObject();
                                fatherNo = fatherNo+(num<10?"0"+num:num);
                                catalog.put("catalogNo", fatherNo);
                                catalog.put("catalog", data.get(1));
                                catalog.put("display", 1);
                                catalogs.add(catalog);
                            }
                        }
                        
                        //是否有小类,有小类必定有中类，这里不考虑有小类没有中类的情况。
                        int isSmell = smell.indexOf(index)>-1?1:0;//这里使用数字表示，数字在后面可用于数据获取。
                        if(isSmell==1)
                        {
                            isin = false;//是否已经存在
                            num = 1;//计算已经有的数量，用于计算编码
                            for (int k = 0; k < catalogs.size(); k++) 
                            {
                                String catalogNo = catalogs.getJSONObject(k).getString("catalogNo");
                                if(data.get(2).equals(catalogs.getJSONObject(k).get("catalog"))&&catalogNo.equals(fatherNo+(num<10?"0"+num:num))) 
                                {
                                    isin = true;
                                    fatherNo = catalogs.getJSONObject(k).getString("catalogNo");
                                    break;
                                }
                                if(catalogNo.indexOf(fatherNo)==0&&!catalogNo.equals(fatherNo)&&catalogNo.length()==8)
                                {
                                    num = num + 1;
                                }
                            }
                            if(!isin)
                            {
                                catalog = new JSONObject();
                                fatherNo = fatherNo+(num<10?"0"+num:num);
                                catalog.put("catalogNo", fatherNo);
                                catalog.put("catalog", data.get(2));
                                catalog.put("display", 0);
                                catalogs.add(catalog);
                            }
                        }
                        
                        int itemNo = 1;
                        //计算itemNo
                        for (int k = 0; k < items.size(); k++) 
                        {
                            if(fatherNo.equals(items.getJSONObject(k).getString("catalogNo"))) { itemNo=itemNo+1;}
                        }
                        
                        JSONObject item = new JSONObject();
                        item.put("catalogNo", fatherNo);
                        item.put("itemNo", itemNo);
                        item.put("ic", data.get(1+isSmell+isMiddling));
                        item.put("ia", data.get(2+isSmell+isMiddling));
                        item.put("qb", data.get(3+isSmell+isMiddling));
                        item.put("so", data.get(4+isSmell+isMiddling));
                        item.put("hb", data.get(5+isSmell+isMiddling));
                        item.put("hc", data.get(6+isSmell+isMiddling));
                        items.add(item);
                    }
                }
                
                //System.out.println(catalogs.toJSONString());
                //System.out.println(items.toJSONString());
                
                String catalog_c = "INSERT INTO `t_hssm_catalog` (`catalogNo`, `catalog`, `display`) VALUES ";
                List<String> catalog_sql = new ArrayList<String>();
                for (int j = 0; j < catalogs.size(); j++) 
                {
                    //catalogNo右侧不足8位补零
                    String catalogNo = catalogs.getJSONObject(j).getString("catalogNo");
                    catalogNo = StringUtils.rightPad(catalogNo, 8, "0");
                    String sql = catalog_c+"("+catalogNo+",'"+catalogs.getJSONObject(j).getString("catalog")+"',"+catalogs.getJSONObject(j).getString("display")+");";
                    sql = sql.replaceAll("null", "");//去除null标识
                    catalog_sql.add(sql);
                }
                
                String item_c = "INSERT INTO `t_hssm_item` (`catalogNo`, `itemNo`, `ic`, `ia`, `qb`, `so`, `hb`, `hc`) VALUES ";
                List<String> item_sql = new ArrayList<String>();
                for (int j = 0; j < items.size(); j++) 
                {
                    //catalogNo右侧不足8位补零
                    String catalogNo = items.getJSONObject(j).getString("catalogNo");
                    catalogNo = StringUtils.rightPad(catalogNo, 8, "0");
                    String sql = item_c+"("+catalogNo+",'"+items.getJSONObject(j).getString("itemNo")+"','"+items.getJSONObject(j).getString("ic")+"','"+items.getJSONObject(j).getString("ia")+"','"+items.getJSONObject(j).getString("qb")+"','"+items.getJSONObject(j).getString("so")+"','"+items.getJSONObject(j).getString("hb")+"','"+items.getJSONObject(j).getString("hc")+"');";
                    sql = sql.replaceAll("null", "");//去除null标识
                    item_sql.add(sql);
                }
                
                try {
                    FileUtils.writeStringToFile(new File(path+sql_path+"/"+directoryName+"/catalogs.json"), catalogs.toString(), "UTF-8");
                    FileUtils.writeStringToFile(new File(path+sql_path+"/"+directoryName+"/items.json"), items.toString(), "UTF-8");
                    
                    FileUtils.writeLines(new File(path+sql_path+"/"+directoryName+"/catalogs.sql"),catalog_sql,true);
                    FileUtils.writeLines(new File(path+sql_path+"/"+directoryName+"/items.sql"),item_sql,true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}